Cloudflare Proxy 導入後に発生した526エラーの原因と解決方法
Zennチームの五十嵐です。
Zennでは2024年2月頃から、CloudflareのProxyを導入しています。導入から2ヶ月ほど経過したある日、Proxyを導入している一部のサービスで、Cloudflareが526エラーを返すようになりました。
本記事では、その原因と解決方法について説明します。
前提
ZennのサービスはGoogle Cloudで稼働しています。
問題が発生したサービスは、Cloud Run + Cloud Load Balancing という構成です。
この構成に、CloudflareのProxyを導入しました。
※画像では「フル」が選択されていますが、当時は「フル(厳密)」が選択されていました。
発生した事象
2024/4/1の18時頃から、Zennの機能の一部である「埋め込み」を返すサービスのエンドポイントが、526エラーを返すようになりました。CloudflareのError 526: invalid SSL certificateは、CloudflareがOriginのSSL証明書の検証に失敗した場合に発生します。
暫定対応として、Cloudflareの「SSL/TLS 暗号化モード」設定を「フル(厳密)」から「フル」に変更し、CloudflareがOriginのSSL証明書の検証をしないように変更しました。
原因
Originのロードバランサに設定されていたSSL証明書の期限更新に失敗しており、期限が切れていました。このSSL証明書は、Googleマネージド証明書の「ロードバランサの承認を使用した Google マネージド証明書」が使われていました。
「ロードバランサの承認を使用した Google マネージド証明書」は、発行した証明書のドメインが、証明書がアタッチされたロードバランサのIPアドレスを指していることで、ドメインの所有権を証明する仕組みです。
証明書の有効期限は90日間で、通常は自動的に更新されますが、CloudflareのProxyを導入したことで、ドメインが指すIPアドレスがCloudflareのIPアドレスに変わってしまったため、証明書の更新に失敗していました。
解決方法
このままの状態でもサービスの提供には問題はないのですが、CloudflareのProxyの導入は検証段階であり、将来的に外す選択肢もありました。このままの状態では、Proxyを外したときに期限切れの証明書が表に出てしまいます。
そこで、Googleマネージド証明書を「DNS 認証を使用した Google マネージド証明書」に切り替えることにしました。「DNS 認証」とは、DNSに特定のレコードを追加することで、ドメインの所有権を証明する仕組みです。
手順
執筆時点で、「DNS 認証を使用した Google マネージド証明書」はGoogle Cloudのコンソールから管理することはできません。gcloudやterraformを使って管理する必要があります。
1. DNS認証を作成する
dns-authorizations create
コマンドでDNS認証に必要な情報を作成します。もし複数のGoogle Cloudプロジェクトで同じドメインのDNS認証を行う場合は、--type="PER_PROJECT_RECORD"
を指定します。(※執筆時点では「プレビュー」ステージの機能です)
$ gcloud certificate-manager dns-authorizations create $AUTHORIZATION_NAME \ --domain=$DOMAIN_NAME \ --type="PER_PROJECT_RECORD"
dns-authorizations describe
コマンドで出力されたCNAMEレコードを、DNSに登録します。
$ gcloud certificate-manager dns-authorizations describe $AUTHORIZATION_NAME dnsResourceRecord: data: {ランダムな値}.authorize.certificatemanager.goog. name: _acme-challenge_{プロジェクトごとに一意な値}.{ドメイン} type: CNAME
2. 証明書を発行する
certificates create
コマンドで証明書を発行します。「DNS認証」の証明書は、ワイドルカード証明書も発行することができます。
$ gcloud certificate-manager certificates create $CERTIFICATE_NAME \ --domains="*.$DOMAIN_NAME,$DOMAIN_NAME" \ --dns-authorizations=$AUTHORIZATION_NAME
certificates describe
コマンドで証明書のステータスが ACTIVE
になるまで待ちます。
$ gcloud certificate-manager certificates describe $CERTIFICATE_NAME
3. 証明書をロードバランサにアタッチする
Zennではロードバランサの設定をterraformで管理しているため、ここからはterraformを使って証明書をロードバランサにアタッチします。
アタッチの方法として、「証明書を直接ロードバランサに設定する方法」と、「証明書マップというリソースを作成してそれをロードバランサに設定する方法」があります。
前者の「証明書を直接ロードバランサに設定する方法」は、google_compute_target_https_proxy
リソースに certificate_manager_certificates
オプションで設定できると説明されているのですが、執筆時点で設定しようとしてもGoogle APIのエラーが返り設定ができませんでした。(なにか条件の見落としがあるのかもしれません。)
ということで、後者の「証明書マップというリソースを作成してそれをロードバランサに設定する方法」を取りました。
証明書マップのリソース
証明書マップのリソースを追加します。
# 証明書マップ resource "google_certificate_manager_certificate_map" "certificate_map" { name = "${var.domain_label}-certmap" description = "${var.domain} certificate map" } # 証明書マップのエントリ resource "google_certificate_manager_certificate_map_entry" "certmap_entry" { name = "${var.certificate_name}-certmap-entry" description = "${var.domain} certificate map entry" map = google_certificate_manager_certificate_map.certificate_map.name certificates = ["projects/${var.project_id}/locations/global/certificates/${var.certificate_name}"] hostname = var.domain } # ロードバランサに設定する証明書マップリソースのIDを出力 output "certificate_map" { value = "//certificatemanager.googleapis.com/${google_certificate_manager_certificate_map.certificate_map.id}" }
ロードバランサのリソース
既存のロードバランサのTargetHttpsProxyのオプションを、 ssl_certificates
から certificate_map
に変更します。
resource "google_compute_target_https_proxy" "target_https_proxy" { name = var.loadbalancer_target_proxy_name quic_override = "ENABLE" # ssl_certificates = [data.google_compute_ssl_certificate.cert.id] # ここを削除 certificate_map = var.certificate_map # ここを追加 url_map = google_compute_url_map.zenn_app_loadbalancer.id }
変更時の注意点として、 ssl_certificates
の削除と certificate_map
の追加を同時に行おうとすると、一時的に証明書が何もアタッチされていない状態になるため、エラーが発生します。そのため、まず certificate_map
を追加して反映、その後、 ssl_certificates
を削除すると、証明書が切り替わります。
そしてこの切替で設定ミスをして、今度は525エラーを発生させてしまったのですが、その話はいつか別の機会に...
おわりに
Googleマネージド証明書が「ロードバランサの承認」という仕組みを利用していること、Googleマネージド証明書に「DNS認証」やその他の証明書発行方法あることなどを、本件を通じて初めて知りました。
また、本件に関して、解決方法を探している中で社内のSlackで質問したところ、Guriさんと岩田さんがすぐにヒントとなる情報をくださいました。幅広い知識を持っていると、問題解決のスピードが段違いで速いですね。ありがとうございました!